﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1;
using O1.Data;
using O1.Data.Traversal;

namespace Tests.O1.Data.Traversal
{
    [TestClass]
    public class EdgeSetTests
    {
        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetContainsIsFalseByDefault()
        {
            new EdgeSet(10).Contains(EdgeDirections.Inbound, 10).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetThrowsArgumentOutOfRangeExceptionWhenInitializedWithNegativeCapacity()
        {
            Action test = () => new EdgeSet(-10);
            test.ShouldThrow<ArgumentOutOfRangeException>();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetContainsIsTrueWhenMatchingEntryExists()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Inbound, 22);
            subject.Contains(EdgeDirections.Inbound, 22).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetContainsIsFalseWhenEntryDiffersByDirection()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Inbound, 22);
            subject.Contains(EdgeDirections.Outbound, 22).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetContainsIsFalseWhenEntryDiffersByType()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Outbound, 21);
            subject.Contains(EdgeDirections.Outbound, 22).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetContainsIsTrueWhenEntryHasBothDirections()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Inbound, 21);
            subject.Add(EdgeDirections.Outbound, 21);
            subject.Contains(EdgeDirections.Inbound, 21).Should().BeTrue();
            subject.Contains(EdgeDirections.Outbound, 21).Should().BeTrue();
            subject.Contains(EdgeDirections.Outbound, 22).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetDuplicateAddDoesNotThrow()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Inbound, 21);
            subject.Add(EdgeDirections.Outbound, 21);
            Action test = () => subject.Add(EdgeDirections.Inbound, 21);
            test.ShouldNotThrow();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeSetExpandsBeyondCapacityAndCanResolveItem()
        {
            var subject = new EdgeSet(3);
            subject.Add(EdgeDirections.Inbound, 100);
            Action test = () =>
                {
                    for (var i = 0; i < 100; i++)
                    {
                        subject.Add(EdgeDirections.Inbound, (ushort)i);
                    }
                };

            test.ShouldNotThrow();
            subject.Contains(EdgeDirections.Inbound, 100).Should().BeTrue();
        }
    }
}
